/**
 * Copyright (C) 2008 aileron.cc
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package cc.aileron.mail.sender;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.Date;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import com.google.inject.Inject;

/**
 * MailSender実装
 * 
 * @author Aileron
 * 
 */
public class MailSenderImpl implements cc.aileron.mail.sender.MailSender
{
    /*
     * (非 Javadoc)
     * 
     * @see cc.aileron.gmail.MailSender#sendMail(cc.aileron.gmail.MailDto)
     */
    public void sendMail(final MailTo dto) throws MessagingException,
            UnsupportedEncodingException
    {
        final MimeMessage mimeMessage = newMessage(dto);
        Transport.send(mimeMessage);
    }

    /**
     * アドレスの配列を取得
     * 
     * @param addressArrayStrings
     * @return
     * @throws AddressException
     */
    private Address[] getAddresses(final String[] addressArrayStrings)
            throws AddressException
    {
        final Address[] result = new Address[addressArrayStrings.length];
        for (int i = 0; i < addressArrayStrings.length; i++)
        {
            final String value = addressArrayStrings[i];
            result[i] = new InternetAddress(value);
        }
        return result;
    }

    /**
     * ファイル添付する際のメッセージ
     * 
     * @param dto
     * @return 送信用メッセージ
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    private MimeMessage multipartMessage(final MailTo dto)
            throws MessagingException, UnsupportedEncodingException
    {
        final MimeMessage mimeMessage = new MimeMessage(from.session);
        mimeMessage.setFrom(from.address);
        mimeMessage.setSubject(dto.subject, encoding);
        mimeMessage.setSentDate(new Date());

        setAddress(mimeMessage, dto);

        final Multipart multipart = new MimeMultipart();
        final MimeBodyPart message = new MimeBodyPart();
        message.setText(dto.text, encoding);
        multipart.addBodyPart(message);

        for (final File file : dto.file)
        {
            final MimeBodyPart part = new MimeBodyPart();
            final FileDataSource dataSource = new FileDataSource(file);
            part.setDataHandler(new DataHandler(dataSource));
            part.setFileName(MimeUtility.encodeWord(dataSource.getName()));
            multipart.addBodyPart(part);
        }

        mimeMessage.setContent(multipart);
        return mimeMessage;
    }

    /**
     * メッセージの作成
     * 
     * @param dto
     * @return 送信用メッセージ
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    private MimeMessage newMessage(final MailTo dto) throws MessagingException,
            UnsupportedEncodingException
    {
        if (dto.file == null || dto.file.size() == 0) { return simpleMessage(dto); }
        return multipartMessage(dto);
    }

    /**
     * 送信先アドレスを設定します
     * 
     * @param message
     * @param dto
     * @throws AddressException
     * @throws MessagingException
     */
    private void setAddress(final MimeMessage message, final MailTo dto)
            throws AddressException, MessagingException
    {
        message.setRecipients(Message.RecipientType.TO, getAddresses(dto.to));

        if (ArrayUtils.isEmpty(dto.cc) == false
                && StringUtils.isEmpty(dto.cc[0]) == false)
        {
            message.setRecipients(Message.RecipientType.CC,
                    getAddresses(dto.cc));
        }

        if (ArrayUtils.isEmpty(dto.bcc) == false
                && StringUtils.isEmpty(dto.bcc[0]) == false)
        {
            message.setRecipients(Message.RecipientType.BCC,
                    getAddresses(dto.bcc));
        }
    }

    /**
     * メッセージのみの単純な MimeMessage
     * 
     * @param dto
     * @return 送信用メッセージ
     * @throws MessagingException
     */
    private MimeMessage simpleMessage(final MailTo dto)
            throws MessagingException
    {
        final MimeMessage mimeMessage = new MimeMessage(from.session);
        mimeMessage
                .setHeader("Content-Type", "text/plain; charset=" + encoding);
        mimeMessage.setFrom(from.address);
        setAddress(mimeMessage, dto);
        mimeMessage.setSubject(dto.subject, encoding);
        mimeMessage.setText(dto.text, encoding);
        mimeMessage.setSentDate(new Date());
        return mimeMessage;
    }

    /**
     * constractor injection
     * 
     * @param from
     * @param setting
     * @throws UnsupportedEncodingException
     */
    @Inject
    public MailSenderImpl(final MailFrom from, final MailSetting setting)
            throws UnsupportedEncodingException
    {
        this.from = from;
        this.encoding = setting.encoding;
    }

    /**
     * from
     */
    private final MailFrom from;

    /**
     * encoding
     */
    private final String encoding;
}